#include <cv.h>
#include <highgui.h>

#include "HandInterface.hpp"
#include "TrackDataServer.hpp"

#include <iostream>

#include <boost/thread.hpp>

using namespace cv;

// Program options example code:
// Copyright Vladimir Prus 2002-2004.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)

#include <boost/program_options.hpp>
namespace po = boost::program_options;

#include <iostream>
#include <iterator>
using namespace std;


Ptr<AbstractTrackerRunner> trackerRunner;

void startTrackerRunner() {
	trackerRunner->run();
}

void doServerCompletionCleanup() {
	trackerRunner->stop();
}

void setSingleTrackerRunner(Ptr< AbstractTrackDataServer >& serverPtr) {
	trackerRunner = new SingleTrackerRunner(serverPtr);
}

void setSingleFaceActivationTrackerRunner(Ptr< AbstractTrackDataServer >& serverPtr) {
	trackerRunner = new SingleTrackerFaceActivationRunner(serverPtr);
}

void setDoubleTrackerRunner(Ptr< AbstractTrackDataServer >& serverPtr) {
	trackerRunner = new DoubleTrackerRunner(serverPtr);
}

int main(int ac, char* av[]) {
	boost::function<void()> startTrackerCallback = &startTrackerRunner;
	boost::function<void()> serverCompletionCallback = &doServerCompletionCleanup;
	
	boost::function<void(Ptr< AbstractTrackDataServer >& serverPtr)> setTrackerRunner;
	
    try {
		
        po::options_description desc("Allowed options");
        desc.add_options()
		("help", "produce help message")
		("double",  "double tracker mode")
		("simple",  "simple tracker mode (no face tracker)")
        ;
		
        po::variables_map vm;        
        po::store(po::parse_command_line(ac, av, desc), vm);
        po::notify(vm);    
		
        if (vm.count("help")) {
            cout << desc << "\n";
            return 1;
        }
		
        if (vm.count("double")) {
            setTrackerRunner = &setDoubleTrackerRunner;
        } else if (vm.count("simple")) {
			setTrackerRunner = &setSingleTrackerRunner;
		} else {
			setTrackerRunner = &setSingleFaceActivationTrackerRunner;
		}

		//Main loop
		while (true) {
			AbstractTrackDataServer* trackDataServerRawPtr = new SynTCPTrackDataServer( startTrackerCallback, serverCompletionCallback );
			Ptr< AbstractTrackDataServer > serverPtr( trackDataServerRawPtr );
			setTrackerRunner( serverPtr );
			int camStatus = trackerRunner->init();
			if ( camStatus != 0 ) {
				return -1; //Could not access camera
			}
			trackDataServerRawPtr->run();
		}
		
    }
    catch(exception& e) {
        cerr << "error: " << e.what() << "\n";
        return 1;
    }
    catch(...) {
        cerr << "Exception of unknown type!\n";
    }
	
    return 0;
}